$.fn.extend({
	"bivariatetable": function(opt) {
		var $this = $(this);
		if (!$this.data("bivariatetable")) {
			function bivariatetable(o) {
				var _bt_ = this;
				_bt_.option = $.extend(true, {
					xaxis: [],
					yaxis: [],
					defaultposition: {x: 0, y: 0},
					defaultvalue: 0,
					defaultcolors: "#aaa",
					defaultbgcolors: "#fff",
					colors: "#333",
					bgcolors: "#ff0",
					xkey: "x",
					ykey: "y",
					reloads: false,
					valuekey: "value",
					drawcell: undefined, //function(celldata)
					data: [],
					onselect: function(callback) {
						callback();
					}
				}, o);
				_bt_.defaultdata = [];

				var _html = [], _html_t = [];

				_html.push('<div class="bivariate-blank"></div>');


				_html.push('<div class="bivariate-xaxis"><ul>');
				for (var x in _bt_.option.xaxis) {
					_html.push('<li data-xaxis="' + _bt_.option.xaxis[x] + '">' + _bt_.option.xaxis[x] + '</li>');
				}
				_html.push('</ul></div>');

				_html.push('<div class="bivariate-yaxis"><ul>');
				for (var y in _bt_.option.yaxis) {
					_html.push('<li data-yaxis="' + _bt_.option.yaxis[y] + '">' + _bt_.option.yaxis[y] + '</li>');
					_html_t.push('<div class="bivariate-table-row" data-yaxis="' + _bt_.option.yaxis[y] + '">');
					for (var x in _bt_.option.xaxis) {
						_html_t.push('<span data-xaxis="' + _bt_.option.xaxis[x] + '" data-yaxis="' + _bt_.option.yaxis[y] + '">' + _bt_.option.defaultvalue + '</span>');
						if (_bt_.option.defaultvalue != null && _bt_.option.defaultvalue != undefined && !(typeof _bt_.option.defaultvalue === 'string' && _bt_.option.defaultvalue == '')) {
							var d = {};
							if ($.isPlainObject(_bt_.option.defaultvalue)) {
								d = $.extend(true, {}, _bt_.option.defaultvalue);
							} else if (_bt_.option.valuekey) {
								d[_bt_.option.valuekey] = _bt_.option.defaultvalue;
							}
							d[_bt_.option.xkey] = _bt_.option.xaxis[x];
							d[_bt_.option.ykey] = _bt_.option.yaxis[y];
							_bt_.defaultdata.push(d);
						}
					}
					_html_t.push('</div>');
				}
				_html.push('</ul></div>');

				_html.push('<div class="bivariate-table">');
				_html.push(_html_t.join(''));
				_html.push('</div>');


				$this.addClass("bivariate-wrap");
				$this.html(_html.join(''));

				$this.find(".bivariate-table > .bivariate-table-row").width($this.find(".bivariate-table > .bivariate-table-row:eq(0) > span").length * $this.find(".bivariate-table > .bivariate-table-row:eq(0) > span:eq(0)").outerWidth());
				$this.find(".bivariate-yaxis > ul").height($this.find(".bivariate-table > .bivariate-table-row > span:last").position().top + $this.find(".bivariate-table").scrollTop() + $this.find(".bivariate-table > .bivariate-table-row > span:last").outerHeight() + 100);
				$this.find(".bivariate-xaxis > ul").width($this.find(".bivariate-table > .bivariate-table-row > span:last").position().left + $this.find(".bivariate-table").scrollLeft() + $this.find(".bivariate-table > .bivariate-table-row > span:last").outerWidth() + 100);

				$this.find(".bivariate-table").scroll(function() {
					$this.find(".bivariate-yaxis").scrollTop($(this).scrollTop());
					$this.find(".bivariate-xaxis").scrollLeft($(this).scrollLeft());
				});

				if (_bt_.option.defaultposition) {
					var _dc = $this.find(".bivariate-table > .bivariate-table-row > span[data-xaxis='" + _bt_.option.defaultposition[_bt_.option.xkey] + "'][data-yaxis='" + _bt_.option.defaultposition[_bt_.option.ykey] + "']");
					_dc.addClass("bivariate-table-defaultposition");
					$this.find(".bivariate-table").scrollTop(_dc.position().top - $this.find(".bivariate-table").height() / 2);
					$this.find(".bivariate-table").scrollLeft(_dc.position().left - $this.find(".bivariate-table").width() / 2);
				}

				var _selectspan = undefined;
				$this.off('mousedown').on("mousedown", ".bivariate-table > .bivariate-table-row > span", function(e) {
					e = e || event;
					if (e.button != 0) return;
					var _s = $(this);
					$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-highlight");
					$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-selected");
					_s.addClass("bivariate-cell-selected");
					_selectspan = _s;
				});



				$this.off('mouseup').on("mouseup", ".bivariate-table > .bivariate-table-row > span", function(e) {
					e = e || event;
					if (e.button != 0) return;
					var _s = $(this);
					if (_selectspan) {
						_selectspan = undefined;
						if (_bt_.option.onselect) {
							_bt_.option.onselect(function(rtn) {
								if (rtn) {
									$this.find(".bivariate-table > .bivariate-table-row > span.bivariate-cell-selected").each(function() {
										var _cell = $(this);
										var _d = _cell.data("data");
										if (!_d) {
											_d = {};
											_d[_bt_.option.xkey] = _cell.data("xaxis");
											_d[_bt_.option.ykey] = _cell.data("yaxis");
										}
										_cell.data("data", $.extend(true, _d, rtn));
										if (_bt_.option.drawcell) {
											_cell.html(_bt_.option.drawcell(_cell.data("data")));
										} else {
											var _value = _cell.data("data")[_bt_.option.valuekey];
											_cell.html(_value);
										}
										_bt_.reColorCell(_cell);
									});
								}
								$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-highlight");
								$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-selected");
							});
						}
					}
				});

				$this.off('mouseover').on("mouseover", ".bivariate-table > .bivariate-table-row > span", function(e) {
					e = e || event;
					if (e.button != 0) return;
					var _s = $(this);
					$this.find(".bivariate-yaxis > ul > li, .bivariate-xaxis > ul > li").removeClass("bivariate-cell-highlight");
					$this.find(".bivariate-yaxis > ul > li[data-yaxis='" + _s.data().yaxis + "'], .bivariate-xaxis > ul > li[data-xaxis='" + _s.data().xaxis + "']").addClass("bivariate-cell-highlight");
					if (_selectspan) {
						_s.addClass("bivariate-cell-selected");
						var _xs = _selectspan.index() > _s.index() ? _s.index() : _selectspan.index();
						var _xe = _selectspan.index() > _s.index() ? _selectspan.index() : _s.index();
						var _ys = _selectspan.parent().index() > _s.parent().index() ? _s.parent().index() : _selectspan.parent().index();
						var _ye = _selectspan.parent().index() > _s.parent().index() ? _selectspan.parent().index() : _s.parent().index();
						$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-selected");
						$this.find(".bivariate-table > .bivariate-table-row:lt(" + (_ye + 1) + "):gt(" + (_ys) + "), .bivariate-table > .bivariate-table-row:eq(" + (_ys) + ")").find("span:lt(" + (_xe + 1) + "):gt(" + (_xs) + "), span:eq(" + (_xs) + ")").addClass("bivariate-cell-selected");
					} else {
						$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-highlight");
						_s.addClass("bivariate-cell-highlight");
					}
				});

				$this.on("mouseout", ".bivariate-table > .bivariate-table-row > span", function(e) {
					e = e || event;
					if (e.button != 0) return;
					var _s = $(this);
					$this.find(".bivariate-yaxis > ul > li, .bivariate-xaxis > ul > li").removeClass("bivariate-cell-highlight");
					if (!_selectspan) {
						$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-highlight");
					}
				});

				_bt_.reColorCell = function(_cell) {
					var _value = _cell.data("data")[_bt_.option.valuekey];
					if (_value != undefined && _value != NaN) {
						if (_value == _bt_.option.defaultvalue) {
							_cell.css("color", _bt_.option.defaultcolors);
							_cell.css("background-color", _bt_.option.defaultbgcolors);
							return;
						}
						if (typeof _bt_.option.colors === 'string') {
							_cell.css("color", _bt_.option.colors);
						} else if ($.isArray(_bt_.option.colors)) {
							for (var c in _bt_.option.colors) {
								if (_bt_.option.colors[c].from <= _value && _bt_.option.colors[c].to >= _value) {
									_cell.css("color", _bt_.option.colors[c].color);
								}
							}
						}
						if (typeof _bt_.option.bgcolors === 'string') {
							_cell.css("background-color", _bt_.option.bgcolors);
						} else if ($.isArray(_bt_.option.bgcolors)) {
							for (var c in _bt_.option.bgcolors) {
								if (_bt_.option.bgcolors[c].from <= _value && _bt_.option.bgcolors[c].to >= _value) {
									_cell.css("background-color", _bt_.option.bgcolors[c].color);
								}
							}
						}
					}
				};

				_bt_.setData = function(data, nodefault) {
					if (nodefault) {
						_bt_.option.data = $.extend(true, [], data);
					} else {
						_bt_.option.data =_bt_.merge(_bt_.defaultdata, data);
					}
					$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-highlight");
					$(".bivariate-table > .bivariate-table-row > span").removeClass("bivariate-cell-selected");
					$(".bivariate-table > .bivariate-table-row > span").data("data", null);
					$(".bivariate-table > .bivariate-table-row > span").removeAttr("style");
					$(".bivariate-table > .bivariate-table-row > span").html("");
					for (var i in _bt_.option.data) {
						var _cell = $this.find(".bivariate-table > .bivariate-table-row > span[data-xaxis='" + _bt_.option.data[i][_bt_.option.xkey] + "'][data-yaxis='" + _bt_.option.data[i][_bt_.option.ykey] + "']");
						_cell.data("data", _bt_.option.data[i]);
						if (_bt_.option.drawcell) {
							_cell.html(_bt_.option.drawcell(_cell.data("data")));
						} else {
							var _value = _cell.data("data")[_bt_.option.valuekey];
							_cell.html(_value);
						}
						_bt_.reColorCell(_cell);
					}
					return _bt_;
				};
				
				_bt_.merge = function(data1, data2) {
					var data3 = [];
					if (data1 && data1.length > 0) {
						if (data2 && data2.length > 0) {
							data3 = $.extend(true, [], data1);
							for (var i in data2) {
								for (var j in data3) {
									if (data3[j][_bt_.option.xkey] == data2[i][_bt_.option.xkey]
									&& data3[j][_bt_.option.ykey] == data2[i][_bt_.option.ykey]) {
										data3[j] = data2[i];
										break;
									}
								}
							}
						} else {
							data3 = $.extend(true, [], data1);
						}
					} else if (data2 && data2.length > 0) {
						data3 = $.extend(true, [], data2);
					} else {
						data3 = [];
					}
					return data3;
				}

				_bt_.setData(_bt_.merge(_bt_.defaultdata, _bt_.option.data));

				_bt_.getData = function() {
					var _data = [];
					 $this.find(".bivariate-table > .bivariate-table-row > span").each(function() {
						if ($(this).data("data")) 	{
							if (_bt_.option.valuekey) {
								if ($(this).data("data")[_bt_.option.valuekey]) {
									_data.push($.extend(true, {}, $(this).data("data")));
								}
							} else {
								_data.push($.extend(true, {}, $(this).data("data")));
							}
						}
					 });
					 return _data;
				}
				return _bt_;
			};

			$this.data("bivariatetable", new bivariatetable(opt));
		}
		return $this.data("bivariatetable");
	}
});